"""
响应解析模块
负责解析AI模型返回的响应并转换为标准格式
"""

import json
import re
import logging
from typing import List, Dict, Any, Optional
from app.models.schemas import TestCase, TestCaseResponse, TestCaseRequest, TestStep
from .reasoning_response_processor import ReasoningResponseProcessor

logger = logging.getLogger(__name__)


class ResponseParser:
    """响应解析器"""

    def __init__(self):
        self.reasoning_processor = ReasoningResponseProcessor()
        self.priority_mapping = {
            'high': 'P1', 'medium': 'P2', 'low': 'P3',
            'critical': 'P1', 'major': 'P2', 'minor': 'P3',
            '高': 'P1', '中': 'P2', '低': 'P3',
            '1': 'P1', '2': 'P2', '3': 'P3', '4': 'P4'
        }

    def parse_response(self, content: str, request: TestCaseRequest) -> TestCaseResponse:
        """解析AI响应内容"""
        logger.info("开始解析AI响应内容")

        # 记录AI返回的原始内容（用于调试）
        logger.info(f"AI返回内容长度: {len(content)}")
        logger.info(f"AI返回原始内容前500字符: {content[:500]}")

        # 处理推理模型响应（如deepseek-r1）
        model_name = getattr(request, 'model_name', None) or getattr(
            request, 'model', None)
        if self.reasoning_processor.is_reasoning_model(model_name):
            logger.info(f"检测到推理模型: {model_name}，开始处理推理响应")
            content = self.reasoning_processor.process_response(
                content, model_name)
            logger.info(f"推理模型处理后内容长度: {len(content)}")

        # 检查内容是否包含test_cases字段
        if 'test_cases' in content:
            logger.info("AI返回内容包含test_cases字段")
        else:
            logger.warning("AI返回内容不包含test_cases字段")

        try:
            # 优先使用推理模型处理器的智能解析
            if self.reasoning_processor.is_reasoning_model(model_name):
                logger.info("使用推理模型智能解析器")
                data = self.reasoning_processor.smart_parse_content(content)

                if data and isinstance(data, dict) and 'test_cases' in data:
                    logger.info("推理模型智能解析器成功解析内容")
                    test_cases = self._extract_test_cases(data)
                    logger.info(f"提取到 {len(test_cases)} 个测试用例")

                    # 构建响应
                    return TestCaseResponse(
                        test_cases=test_cases,
                        test_scenarios=[],
                        test_types=["functional"],
                        test_executors=["qa"],
                        test_design_methods=["use_case"],
                        estimated_effort=f"约{len(test_cases) * 30}分钟",
                        requirement=request.requirement or "",
                        project_name=request.project_name or "",
                        module_name=request.module_name or ""
                    )
                else:
                    logger.warning("推理模型智能解析器未能提取到有效数据，尝试其他方法")
                    # 记录更详细的调试信息
                    if data:
                        logger.debug(f"推理模型解析器返回的数据类型: {type(data)}")
                        logger.debug(
                            f"推理模型解析器返回的数据键: {list(data.keys()) if isinstance(data, dict) else 'N/A'}")
                        logger.debug(f"推理模型解析器返回的数据前200字符: {str(data)[:200]}")
                    else:
                        logger.debug("推理模型解析器返回None")

            # 使用增强的JSON解析器
            try:
                from enhanced_json_parser import EnhancedJSONParser
                enhanced_parser = EnhancedJSONParser()
                data = enhanced_parser.parse(content)

                if data and isinstance(data, dict) and 'test_cases' in data:
                    logger.info("增强JSON解析器成功解析内容")
                    test_cases = self._extract_test_cases(data)
                    logger.info(f"提取到 {len(test_cases)} 个测试用例")

                    # 构建响应
                    return TestCaseResponse(
                        test_cases=test_cases,
                        test_scenarios=[],
                        test_types=["functional"],
                        test_executors=["qa"],
                        test_design_methods=["use_case"],
                        estimated_effort=f"约{len(test_cases) * 30}分钟",
                        requirement=request.requirement or "",
                        project_name=request.project_name or "",
                        module_name=request.module_name or ""
                    )
                else:
                    logger.warning("增强JSON解析器未能提取到有效数据，尝试传统方法")
                    raise ValueError("增强解析器失败")

            except ImportError:
                logger.warning("增强JSON解析器不可用，使用传统方法")
                raise ValueError("增强解析器不可用")

        except Exception as e:
            logger.warning(f"增强解析失败，尝试传统解析: {str(e)}")

            # 回退到传统解析方法
            try:
                # 清理和提取JSON
                json_content = self._extract_json(content)
                if not json_content:
                    logger.error("无法从响应中提取有效的JSON内容")
                    raise ValueError("无法从响应中提取有效的JSON内容")

                logger.info("JSON格式正确，无需修复")

                # 解析JSON
                data = json.loads(json_content)
                logger.info(f"成功解析JSON，包含字段: {list(data.keys())}")

                # 提取测试用例
                test_cases = self._extract_test_cases(data)
                logger.info(f"提取到 {len(test_cases)} 个测试用例")

                # 构建响应
                return TestCaseResponse(
                    test_cases=test_cases,
                    test_scenarios=[],
                    test_types=["functional"],
                    test_executors=["qa"],
                    test_design_methods=["use_case"],
                    estimated_effort=f"约{len(test_cases) * 30}分钟",
                    requirement=request.requirement or "",
                    project_name=request.project_name or "",
                    module_name=request.module_name or ""
                )

            except Exception as e2:
                logger.error(f"传统解析也失败: {str(e2)}")
                # 尝试从原始内容中提取测试用例
                return self._fallback_parse(content, request)

    def _extract_json(self, content: str) -> Optional[str]:
        """从内容中提取JSON字符串"""
        if not content:
            return None

        # 移除可能的markdown代码块标记
        content = re.sub(r'```json\s*', '', content)
        content = re.sub(r'```\s*$', '', content)
        content = content.strip()

        # 尝试直接解析
        if content.startswith('{') and content.endswith('}'):
            # 验证是否为有效JSON
            try:
                parsed = json.loads(content)
                if isinstance(parsed, dict) and 'test_cases' in parsed:
                    logger.info("直接解析JSON成功")
                    return content
            except json.JSONDecodeError as e:
                logger.warning(f"直接解析JSON失败: {str(e)}")

        # 使用更强大的JSON提取策略
        json_candidates = []

        # 策略1: 查找包含test_cases的JSON块
        test_cases_patterns = [
            # 匹配完整的JSON对象，支持嵌套
            r'\{(?:[^{}]|{(?:[^{}]|{[^{}]*})*})*"test_cases"(?:[^{}]|{(?:[^{}]|{[^{}]*})*})*\}',
            # 更宽松的匹配
            r'\{.*?"test_cases".*?\}',
        ]

        for pattern in test_cases_patterns:
            matches = re.findall(pattern, content, re.DOTALL | re.MULTILINE)
            json_candidates.extend(matches)

        # 策略2: 查找所有可能的JSON块
        all_json_pattern = r'\{[^{}]*(?:{[^{}]*}[^{}]*)*\}'
        all_matches = re.findall(all_json_pattern, content, re.DOTALL)
        json_candidates.extend(all_matches)

        # 策略3: 手动查找JSON边界
        brace_count = 0
        start_pos = -1
        for i, char in enumerate(content):
            if char == '{':
                if brace_count == 0:
                    start_pos = i
                brace_count += 1
            elif char == '}':
                brace_count -= 1
                if brace_count == 0 and start_pos != -1:
                    candidate = content[start_pos:i+1]
                    json_candidates.append(candidate)
                    start_pos = -1

        # 验证和选择最佳候选
        for candidate in json_candidates:
            try:
                parsed = json.loads(candidate)
                if isinstance(parsed, dict) and 'test_cases' in parsed:
                    logger.info("成功提取包含test_cases的JSON")
                    return candidate
            except json.JSONDecodeError:
                continue

        # 尝试修复常见的JSON格式问题
        fixed_content = self._fix_json_format(content)
        if fixed_content:
            return fixed_content

        logger.error("所有JSON提取策略都失败了")
        return None

    def _fix_json_format(self, content: str) -> Optional[str]:
        """尝试修复常见的JSON格式问题"""
        if not content:
            return None

        try:
            # 移除多余的文本
            content = content.strip()

            # 查找可能的JSON开始和结束位置
            start_pos = content.find('{')
            if start_pos == -1:
                return None

            # 从后往前查找最后一个}
            end_pos = content.rfind('}')
            if end_pos == -1 or end_pos <= start_pos:
                return None

            # 提取JSON部分
            json_part = content[start_pos:end_pos + 1]

            # 尝试修复常见问题
            fixes = [
                # 修复尾随逗号
                lambda x: re.sub(r',\s*}', '}', x),
                lambda x: re.sub(r',\s*]', ']', x),
                # 修复缺少引号的键
                lambda x: re.sub(r'(\w+):', r'"\1":', x),
                # 修复单引号
                lambda x: x.replace("'", '"'),
                # 修复换行符问题
                lambda x: x.replace('\n', '\\n').replace(
                    '\r', '\\r').replace('\t', '\\t'),
            ]

            for fix in fixes:
                try:
                    fixed = fix(json_part)
                    parsed = json.loads(fixed)
                    if isinstance(parsed, dict) and 'test_cases' in parsed:
                        logger.info("成功修复JSON格式问题")
                        return fixed
                except (json.JSONDecodeError, Exception):
                    continue

            return None

        except Exception as e:
            logger.warning(f"JSON修复失败: {str(e)}")
            return None

    def _extract_test_cases(self, data: Dict[str, Any]) -> List[TestCase]:
        """从解析的数据中提取测试用例"""
        test_cases = []

        # 获取测试用例列表
        cases_data = data.get('test_cases', [])
        if not cases_data:
            logger.warning("响应中没有找到test_cases字段")
            return []

        logger.info(f"提取到test_cases数组，长度: {len(cases_data)}")

        for i, case_data in enumerate(cases_data):
            try:
                test_case = self._create_test_case(case_data, i + 1)
                test_cases.append(test_case)
                logger.debug(f"成功解析第{i+1}个测试用例: {test_case.title}")
            except Exception as e:
                logger.warning(f"解析第{i+1}个测试用例失败: {str(e)}")
                logger.debug(f"失败的测试用例数据: {case_data}")
                continue

        logger.info(f"AI生成了{len(test_cases)}个用例")
        return test_cases

    def _create_test_case(self, case_data: Dict[str, Any], index: int) -> TestCase:
        """创建单个测试用例对象"""
        # 生成ID
        case_id = case_data.get('id', f'TC{index:03d}')
        if not case_id.startswith('TC'):
            case_id = f'TC{index:03d}'

        # 解析测试步骤
        steps = self._parse_steps(case_data.get('steps', []))

        # 标准化优先级
        priority = self._normalize_priority(case_data.get('priority', 'P2'))

        return TestCase(
            id=case_id,
            title=case_data.get('title', f'测试用例{index}'),
            preconditions=case_data.get('preconditions', '无'),
            steps=steps,
            priority=priority,
            category=case_data.get('category', '功能测试'),
            test_type=case_data.get('test_type', 'functional'),
            test_executor=case_data.get('test_executor', 'qa'),
            test_design_method=case_data.get('test_design_method', 'use_case'),
            test_data=case_data.get('test_data', {}),
            notes=case_data.get('notes', '')
        )

    def _parse_steps(self, steps_data: List[Any]) -> List[TestStep]:
        """解析测试步骤"""
        steps = []

        for i, step_data in enumerate(steps_data):
            if isinstance(step_data, dict):
                step = TestStep(
                    step_number=step_data.get('step_number', i + 1),
                    description=step_data.get('description', f'步骤{i+1}'),
                    expected_result=step_data.get('expected_result', ''),
                    test_data=step_data.get('test_data', {})
                )
            elif isinstance(step_data, str):
                # 如果是字符串，转换为步骤对象
                step = TestStep(
                    step_number=i + 1,
                    description=step_data,
                    expected_result='',
                    test_data={}
                )
            else:
                continue

            steps.append(step)

        return steps

    def _normalize_priority(self, priority: str) -> str:
        """标准化优先级"""
        if not priority:
            return 'P2'

        priority_lower = str(priority).lower().strip()
        return self.priority_mapping.get(priority_lower, priority)

    def _fallback_parse(self, content: str, request: TestCaseRequest) -> TestCaseResponse:
        """回退解析方法"""
        logger.info("使用回退解析方法")

        # 尝试从文本中提取测试用例信息
        test_cases = []

        # 简单的文本解析逻辑
        lines = content.split('\n')
        current_case = {}
        case_count = 0

        for line in lines:
            line = line.strip()
            if not line:
                continue

            # 检查是否是新的测试用例开始
            if any(keyword in line.lower() for keyword in ['测试用例', 'test case', 'tc']):
                if current_case:
                    test_case = self._create_fallback_test_case(
                        current_case, case_count)
                    if test_case:
                        test_cases.append(test_case)
                        case_count += 1
                current_case = {'title': line}
            elif '前置条件' in line or 'precondition' in line.lower():
                current_case['preconditions'] = line.split(
                    '：')[-1].split(':')[-1].strip()
            elif '测试步骤' in line or 'step' in line.lower():
                current_case['steps'] = [line.split(
                    '：')[-1].split(':')[-1].strip()]
            elif '预期结果' in line or 'expected' in line.lower():
                current_case['expected'] = line.split(
                    '：')[-1].split(':')[-1].strip()

        # 处理最后一个用例
        if current_case:
            test_case = self._create_fallback_test_case(
                current_case, case_count)
            if test_case:
                test_cases.append(test_case)

        # 如果没有解析到任何用例，创建一个默认用例
        if not test_cases:
            test_cases = [self._create_default_test_case()]

        return TestCaseResponse(
            test_cases=test_cases,
            test_scenarios=[],
            test_types=["functional"],
            test_executors=["qa"],
            test_design_methods=["use_case"],
            estimated_effort=f"约{len(test_cases) * 30}分钟",
            requirement=request.requirement or "",
            project_name=request.project_name or "",
            module_name=request.module_name or ""
        )

    def _create_fallback_test_case(self, case_data: Dict[str, Any], index: int) -> Optional[TestCase]:
        """创建回退测试用例"""
        try:
            steps = [TestStep(
                step_number=1,
                description=case_data.get('steps', ['执行测试操作'])[0],
                expected_result=case_data.get('expected', '操作成功'),
                test_data={}
            )]

            return TestCase(
                id=f'TC{index+1:03d}',
                title=case_data.get('title', f'测试用例{index+1}'),
                preconditions=case_data.get('preconditions', '无'),
                steps=steps,
                priority='P2',
                category='功能测试',
                test_type='functional',
                test_executor='qa',
                test_design_method='use_case',
                test_data={},
                notes=''
            )
        except Exception as e:
            logger.warning(f"创建回退测试用例失败: {str(e)}")
            return None

    def _create_default_test_case(self) -> TestCase:
        """创建默认测试用例"""
        return TestCase(
            id='TC001',
            title='默认测试用例',
            preconditions='系统正常运行',
            steps=[TestStep(
                step_number=1,
                description='执行基本功能测试',
                expected_result='功能正常',
                test_data={}
            )],
            priority='P2',
            category='功能测试',
            test_type='functional',
            test_executor='qa',
            test_design_method='use_case',
            test_data={},
            notes='AI解析失败时的默认用例'
        )
